package com.dkd.manage.service.impl;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import cn.hutool.core.util.StrUtil;
import com.dkd.common.constant.DkdContants;
import com.dkd.common.core.domain.entity.SysUser;
import com.dkd.common.exception.ServiceException;
import com.dkd.common.utils.DateUtils;
import com.dkd.common.utils.SecurityUtils;
import com.dkd.common.utils.spring.SpringUtils;
import com.dkd.manage.domain.Emp;
import com.dkd.manage.domain.TaskDetails;
import com.dkd.manage.domain.VendingMachine;
import com.dkd.manage.domain.dto.TaskDto;
import com.dkd.manage.domain.vo.TaskVo;
import com.dkd.manage.mapper.EmpMapper;
import com.dkd.manage.mapper.TaskDetailsMapper;
import com.dkd.manage.mapper.VendingMachineMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.dkd.manage.mapper.TaskMapper;
import com.dkd.manage.domain.Task;
import com.dkd.manage.service.ITaskService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 工单管理Service业务层处理
 *
 * @author guowenjie
 * @date 2025-06-24
 */
@Service
public class TaskServiceImpl implements ITaskService {
    @Autowired
    private TaskMapper taskMapper;

    @Autowired
    private VendingMachineMapper vendingMachineMapper;

    @Autowired
    private EmpMapper empMapper;

    @Autowired
    private TaskDetailsMapper taskDetailsMapper;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 查询工单管理
     *
     * @param taskId 工单管理主键
     * @return 工单管理
     */
    @Override
    public Task selectTaskByTaskId(Long taskId) {
        return taskMapper.selectTaskByTaskId(taskId);
    }

    /**
     * 查询工单管理列表
     *
     * @param task 工单管理
     * @return 工单管理
     */
    @Override
    public List<Task> selectTaskList(Task task) {
        return taskMapper.selectTaskList(task);
    }

    /**
     * 新增工单管理
     *
     * @param task 工单管理
     * @return 结果
     */
    @Override
    public int insertTask(Task task) {
        task.setCreateTime(DateUtils.getNowDate());
        return taskMapper.insertTask(task);
    }

    /**
     * 修改工单管理
     *
     * @param task 工单管理
     * @return 结果
     */
    @Override
    public int updateTask(Task task) {
        task.setUpdateTime(DateUtils.getNowDate());
        return taskMapper.updateTask(task);
    }

    /**
     * 批量删除工单管理
     *
     * @param taskIds 需要删除的工单管理主键
     * @return 结果
     */
    @Override
    public int deleteTaskByTaskIds(Long[] taskIds) {
        return taskMapper.deleteTaskByTaskIds(taskIds);
    }

    /**
     * 删除工单管理信息
     *
     * @param taskId 工单管理主键
     * @return 结果
     */
    @Override
    public int deleteTaskByTaskId(Long taskId) {
        return taskMapper.deleteTaskByTaskId(taskId);
    }

    /**
     * 查询不同类型工单
     *
     * @param task taskType: true运维工单 false运营工单
     * @return 结果
     */
    @Override
    public List<TaskVo> selectTaskVoList(Task task) {
        return taskMapper.selectTaskVoList(task);
    }

    /**
     * 创建运营工单和运维工单
     *
     * @param taskDto 工单信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertTaskDto(TaskDto taskDto) {
        int rs;
        String innerCode = taskDto.getInnerCode();
        //查询售货机是否存在,不存在结束
        if (innerCode == null) {
            throw new ServiceException("售货机编号不能为空");
        }
        VendingMachine vendingMachine = vendingMachineMapper.selectVendingMachineByInnerCode(innerCode);
        if (vendingMachine == null) {
            throw new ServiceException("设备不存在");
        }

        //校验工单类型
        checkTask(taskDto, vendingMachine);

        //校验运营人员是否存在,不存在结束
        checkEmp(taskDto, vendingMachine);


        // 根据售货机编号 工单类型 工单状态 查询工单是否存在,如果存在,结束
        hasTask(taskDto, innerCode);


        // 校验都通过,创建工单
        Task newTask = new Task();

        //业务key: task.code  业务值:202505050001 日期+icr自增值
        String key = "task.code";
        String dateStr = DateUtils.getDate().replaceAll("-", "");
        String code = "";
        if (redisTemplate.opsForValue().get(key) == null) {
            //设置初始递增值
            Long increment = redisTemplate.opsForValue().increment(key, 1);
            redisTemplate.opsForValue().set(key, increment.toString(),1,TimeUnit.DAYS);
//            redisTemplate.opsForValue().set(key, increment.toString(),1,TimeUnit.MINUTES);
            code = dateStr + StrUtil.padPre(redisTemplate.opsForValue().get(key), 4, "0");
        } else {
            //递增值
            Long increment = redisTemplate.opsForValue().increment(key);
            code = dateStr + StrUtil.padPre(increment.toString(), 4, "0");
        }

        newTask.setTaskCode(code);
        // 工单状态设置待处理
        newTask.setTaskStatus(DkdContants.TASK_STATUS_CREATE);
        // 创建类型 手动
        newTask.setCreateType(1L);
        // 设置售货机编码
        newTask.setInnerCode(innerCode);
        // 设置执行人id 执行人姓名 所属区域
        newTask.setUserId(taskDto.getUserId());
        newTask.setUserName(empMapper.selectEmpById(taskDto.getUserId()).getUserName());
        newTask.setRegionId(vendingMachine.getRegionId());
        // 设置备注 工单类型 指派人id(当前的登录人) 地址 创建时间 修改时间
        newTask.setDesc(taskDto.getDesc());
        newTask.setProductTypeId(taskDto.getProductTypeId());
        newTask.setAssignorId(SecurityUtils.getLoginUser().getUserId());
        newTask.setAddr(vendingMachine.getAddr());
        newTask.setCreateTime(DateUtils.getNowDate());
        newTask.setUpdateTime(DateUtils.getNowDate());
        //保存工单
        rs = taskMapper.insertTask(newTask);


        if (taskDto.getProductTypeId().equals(DkdContants.TASK_TYPE_SUPPLY)) {
            //是运营工单,保存工单详情
            Long taskId = newTask.getTaskId();
            if (taskDto.getDetails() == null && taskDto.getDetails().size() == 0) {
                throw new ServiceException("请选择补货商品");
            }
            List<TaskDetails> taskDetailList = taskDto.getDetails().stream().map(taskDetail -> {
                TaskDetails taskDetails = new TaskDetails();
                taskDetails.setTaskId(taskId);
                taskDetails.setChannelCode(taskDetail.getChannelCode());
                taskDetails.setExpectCapacity(taskDetail.getExpectCapacity());
                taskDetails.setSkuId(taskDetail.getSkuId());
                taskDetails.setSkuName(taskDetail.getSkuName());
                taskDetails.setSkuImage(taskDetail.getSkuImage());
                return taskDetails;
            }).collect(Collectors.toList());
            //批量保存工单详情
            rs = taskDetailsMapper.insertTaskDetailsBatch(taskDetailList);
        }


        return rs;
    }


    // 检查当前创建的工单是否存在
    private void hasTask(TaskDto taskDto, String innerCode) {
        Task taskParam = new Task();
        taskParam.setInnerCode(innerCode);
        taskParam.setProductTypeId(taskDto.getProductTypeId());
        taskParam.setTaskStatus(DkdContants.TASK_STATUS_CREATE);
        List<Task> taskList = taskMapper.selectTaskList(taskParam);
        if (taskList != null && taskList.size() > 0) {
            throw new ServiceException("工单已存在,请勿重复创建工单");
        }
    }

    // 校验运营人员是否存在,不存在结束
    private void checkEmp(TaskDto taskDto, VendingMachine vendingMachine) {
        Long userId = taskDto.getUserId();
        if (userId == null) {
            throw new ServiceException("请选择操作人员");
        }
        Emp emp = empMapper.selectEmpById(userId);
        if (emp == null) {
            throw new ServiceException("操作人员不存在");
        }

        //如果存在,判断角色是否运维或运营 且 所属区域和售货机所属区域一致,如果不一致,结束
        String roleCode = emp.getRoleCode();
        if (!roleCode.equals(DkdContants.ROLE_CODE_OPERATOR) && !roleCode.equals(DkdContants.ROLE_CODE_BUSINESS)) {
            throw new ServiceException("操作人员角色错误");
        }
        if (!emp.getRegionId().equals(vendingMachine.getRegionId())) {
            throw new ServiceException("操作人员所属区域不一致");
        }
    }

    //校验投放工单 补货工单 维修工单 撤机工单是否符合规则
    private static void checkTask(TaskDto taskDto, VendingMachine vendingMachine) {
        //  投放工单: 如果是投放工单 且 状态为运行状态,抛出异常(未投放 撤机都无法投放)
        if (taskDto.getProductTypeId().equals(DkdContants.TASK_TYPE_DEPLOY) &&
                vendingMachine.getVmStatus().equals(DkdContants.VM_STATUS_RUNNING)) {
            throw new ServiceException("设备正在运行中,无法投放");
        }
        //  补货工单: 如果是补货工单 且 状态为非运行状态,抛出异常(未投放 撤机都无法补货)
        if (taskDto.getProductTypeId().equals(DkdContants.TASK_TYPE_SUPPLY) &&
                !vendingMachine.getVmStatus().equals(DkdContants.VM_STATUS_RUNNING)) {
            throw new ServiceException("设备未运行中,无法补货");
        }
        //  维修工单: 如果是维修工单 且 状态为非运行状态,抛出异常(未投放 撤机都无法维修)
        if (taskDto.getProductTypeId().equals(DkdContants.TASK_TYPE_REPAIR) &&
                !vendingMachine.getVmStatus().equals(DkdContants.VM_STATUS_RUNNING)) {
            throw new ServiceException("设备未运行中,无法维修");
        }
        //  撤机工单: 如果是撤机工单 且 状态为非运行状态,抛出异常(未投放 撤机都无法撤机)
        if (taskDto.getProductTypeId().equals(DkdContants.TASK_TYPE_REVOKE)
                && !vendingMachine.getVmStatus().equals(DkdContants.VM_STATUS_RUNNING)) {
            throw new ServiceException("设备未运行中,无法撤机");
        }
    }


    /**
     * 取消工单
     *
     * @param task 工单信息
     * @return 结果
     */
    @Override
    public int cancel(Task task) {
        //校验工单状态
        Task taskDb = taskMapper.selectTaskByTaskId(task.getTaskId());
        // 如果工单状态为已取消,则不能取消
        if (taskDb.getTaskStatus().equals(DkdContants.TASK_STATUS_CANCEL)) {
            throw new ServiceException("当前工单已取消,无法再次取消");
        }
        // 如果工单为完成,则不能取消
        if (taskDb.getTaskStatus().equals(DkdContants.TASK_STATUS_FINISH)) {
            throw new ServiceException("当前工单已完成,无法再次取消");
        }

        // 修改工单状态为已取消 取消原因 更新时间
        task.setTaskStatus(DkdContants.TASK_STATUS_CANCEL);
        task.setUpdateTime(DateUtils.getNowDate());
        return taskMapper.updateTask(task);
    }
}
